﻿#pragma once

#include <chrono>
#include <cstdint>
#include <map>
#include <vector>

#include "asycipc/frame.hpp"

namespace asycipc {

class SlidingWindow {
 public:
  struct RetryItem {
    Frame frame;
    uint32_t attempt = 0;
  };

  SlidingWindow(std::size_t window_size,
                std::chrono::milliseconds base_retry,
                uint32_t max_attempts);

  std::size_t window_size() const noexcept { return window_size_; }
  std::size_t PendingCount() const noexcept { return pending_.size(); }
  bool IsFull() const noexcept { return pending_.size() >= window_size_; }

  void Push(const Frame& frame, std::chrono::steady_clock::time_point now);
  bool MarkAck(uint64_t seq);
  bool MarkNack(uint64_t seq, std::chrono::steady_clock::time_point now);
  std::vector<RetryItem> CollectRetries(std::chrono::steady_clock::time_point now);

 private:
  struct PendingEntry {
    Frame frame;
    std::chrono::steady_clock::time_point next_retry;
    uint32_t attempts = 0;
  };

  std::size_t window_size_;
  std::chrono::milliseconds base_retry_;
  uint32_t max_attempts_;
  std::map<uint64_t, PendingEntry> pending_;
};

}  // namespace asycipc
